﻿
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing.Imaging;



namespace EXEStart
{
    /// <summary>
    /// Ico图标大小
    /// : Jumbo：255*255  
    /// / Large：48*48  
    /// / Norma：32*32  
    /// / Small：24*24 
    /// </summary>
    public enum IconSize
    {
        Jumbo = 255,
        Large = 48,
        Norma = 32,
        Small = 24
    }

    class GetFileIcon
    {
        //2个WORD组成DWORD
        //private uint MAKELONG(ushort a, ushort b) => ((uint)(((ushort)(a)) | ((uint)((ushort)(b))) << 16));

        /// <summary>
        /// 依据文件名读取图标，若指定文件不存在，则返回空值。
        /// </summary>
        /// <param name="fileName">文件路径</param>
        /// <param name="isLarge">是否返回大图标</param>
        /// <returns></returns>
        public static Icon GetIconByFileName(string fileName, bool isLarge = true)
        {
            IntPtr[] phiconLarge;
            IntPtr[] phiconSmall;

            IntPtr IconHnd = IntPtr.Zero;
            try
            {
                ExtractIconEx(fileName, 0, out phiconLarge, out phiconSmall, 1);
                IconHnd = isLarge ? phiconLarge[0] : phiconSmall[0];
            }
            catch
            {
                return null;
            }
            return (IconHnd == IntPtr.Zero) ? null : Icon.FromHandle(IconHnd);
        }


        /// <summary>  
        /// 根据文件扩展名（如:.txt），返回与之关联的图标。
        /// 若不以"."开头则返回文件夹的图标。  
        /// </summary>  
        /// <param name="fileType">文件扩展名</param>  
        /// <param name="iconSize">指定图标大小，默认中等图标48*48</param>  
        /// <returns></returns>  
        public static Icon[] GetIconByFileTypes(string fileType, IconSize iconSize = IconSize.Large)
        {
            int nIconIndex;
            string TruePath = GetFileTypeIconPath(fileType, out nIconIndex);

            Icon[] resultIcon = null;
            try
            {
                resultIcon = GetIcons(TruePath, iconSize);
            }
            catch { }
            return resultIcon;
        }


        public static Icon GetIconByFileType(string fileType, IconSize iconSize = IconSize.Large)
        {
            int nIconIndex;
            string TruePath = GetFileTypeIconPath(fileType, out nIconIndex);

            Icon resultIcon = null;
            try
            {
                resultIcon = GetIcon(TruePath, nIconIndex, iconSize);
            }
            catch { }
            return resultIcon;
        }

        /// <summary>
        /// 获取指定类型文件关联的图标文件路径
        /// </summary>
        /// <param name="fileType">文件类型</param>
        /// <param name="nIconIndex">图标索引</param>
        /// <returns></returns>
        private static string GetFileTypeIconPath(string fileType, out int nIconIndex)
        {
            nIconIndex = 0;
            if(string.IsNullOrEmpty(fileType)) return "";

            RegistryKey regVersion = null;
            string regFileType = null;
            string regIconString = null;
            string systemDirectory = Environment.SystemDirectory + "\\";

            if(fileType[0] == '.')
            {
                //读系统注册表中文件类型信息  
                regVersion = Registry.ClassesRoot.OpenSubKey(fileType, true);
                if(regVersion != null)
                {
                    regFileType = regVersion.GetValue("") as string;
                    regVersion.Close();
                    regVersion = Registry.ClassesRoot.OpenSubKey(regFileType + @"\DefaultIcon", true);
                    if(regVersion != null)
                    {
                        regIconString = regVersion.GetValue("") as string;
                        regVersion.Close();
                    }
                }
                if(regIconString == null)
                {
                    //没有读取到文件类型注册信息，指定为未知文件类型的图标  
                    regIconString = systemDirectory + "shell32.dll,0";
                }
            }
            else
            {
                //直接指定为文件夹图标  
                regIconString = systemDirectory + "shell32.dll,3";
            }
            string[] fileIcon = regIconString.Split(new char[] { ',' });

            if(fileIcon.Length != 2)
            {
                //系统注册表中注册的标图不能直接提取，则返回可执行文件的通用图标  
                fileIcon = new string[] { systemDirectory + "shell32.dll", "2" };
            }

            //处理注册表文件路径外面的引号
            if(fileIcon[0][0] == '\"')
            {
                string str = fileIcon[0];
                fileIcon[0] = str.Substring(str.IndexOf('\"') + 1, str.LastIndexOf('\"') - 1);
            }

            nIconIndex = int.Parse(fileIcon[1]);
            return fileIcon[0];
        }

        /// <summary>
        /// 获取全部图标
        /// </summary>
        /// <param name="sFileName">文件名</param>
        /// <param name="iconSize">图标大小</param>
        /// <param name="nIcon">要获取的图标数量</param>
        /// <returns>图标数组</returns>
        public static Icon[] GetIcons(string sFileName, IconSize iconSize = IconSize.Large, uint nIcon = 0)
        {
            //选中文件中的图标总数
            uint iconTotalCount = PrivateExtractIcons(sFileName, 0, 0, 0, null, null, 0, 0);
            iconTotalCount = (nIcon > iconTotalCount) ? iconTotalCount : nIcon;

            //用于接收获取到的图标指针
            IntPtr[] hIcons = new IntPtr[iconTotalCount];

            //对应的图标id
            uint[] nIcons = new uint[iconTotalCount];

            //成功获取到的图标个数
            uint successCount = PrivateExtractIcons(sFileName, 0, (int)iconSize, (int)iconSize, hIcons, nIcons, iconTotalCount, 0);

            List<Icon> icons = new();

            //遍历并转换图标类型
            foreach(IntPtr p in hIcons)
            {
                //指针为空，跳过
                if(p == IntPtr.Zero) continue;

                using(Icon ico = Icon.FromHandle(p))
                {
                    icons.Add((Icon)ico.Clone());
                    DestroyIcon(p);
                }
            }

            return icons.ToArray();
        }

        /// <summary>
        /// 获取单个图标
        /// </summary>
        /// <param name="sFileName">文件名</param>
        /// <param name="nIconIndex">图标索引号</param>
        /// <param name="iconSize">图标大小</param>
        /// <returns></returns>
        public static Icon GetIcon(string sFileName, int nIconIndex = 0, IconSize iconSize = IconSize.Large)
        {
            //选中文件中的图标总数
            uint iconTotalCount = PrivateExtractIcons(sFileName, 0, 0, 0, null, null, 0, 0);
            if(iconTotalCount == 0 || nIconIndex > iconTotalCount) return null;

            //用于接收获取到的图标指针
            IntPtr[] hIcons = new IntPtr[1];
            //对应的图标id
            uint[] nIcons = new uint[1];
            //成功获取到的图标个数
            uint successCount = PrivateExtractIcons(sFileName, nIconIndex, (int)iconSize, (int)iconSize, hIcons, nIcons, 1, 0);

            Icon icon = null;
            using(Icon ico = Icon.FromHandle(hIcons[0]))
            {
                icon = (Icon)ico.Clone();
                DestroyIcon(hIcons[0]);
            }

            return icon;
        }


        /// <summary>
        /// 获取文件图标，只能获取32*32的大图标和24*24的小图标
        /// </summary>
        [DllImport("shell32.dll")]
        private static extern uint ExtractIconEx(string lpszFile, int nIconIndex, out IntPtr[] phiconLarge, out IntPtr[] phiconSmall, uint nIcons);

        //https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-loadimagew
        //flags标志
        private const int LR_DEFAULTCOLOR = 0x0;    //默认标志；它什么都不做。它的意思是“不是LR_MONOCHROME(黑白) ”
        private const int LR_VGACOLOR = 0x80;   //使用真正的 VGA 颜色


        //https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-privateextracticonsw
        /// <summary>
        /// 获取文件图标，可自定义大小
        /// </summary>
        /// <param name="lpszFile">文件名可以是exe,dll,ico,cur,ani,bmp</param>
        /// <param name="nIconIndex">从第几个图标开始获取</param>
        /// <param name="cxIcon">获取图标的尺寸x</param>
        /// <param name="cyIcon">获取图标的尺寸y</param>
        /// <param name="phicon">获取到的图标指针数组</param>
        /// <param name="piconid">图标对应的资源编号</param>
        /// <param name="nIcons">指定获取的图标数量，仅当文件类型为.exe 和 .dll时候可用</param>
        /// <param name="flags">标志，默认0就可以，具体可以看LoadImage函数</param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public static extern uint PrivateExtractIcons(string lpszFile, int nIconIndex, int cxIcon, int cyIcon, IntPtr[] phicon, uint[] piconid, uint nIcons, uint flags);

        //https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-destroyicon?redirectedfrom=MSDN
        /// <summary>
        /// 销毁图标
        /// </summary>
        /// <param name="hIcon">图标句柄</param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public static extern bool DestroyIcon(IntPtr hIcon);



        public static Image ResizeImage(Image originalImage, int size)
        {
            Bitmap resizedImage = new Bitmap(originalImage, size, size);

           /* Bitmap resizedImage = new Bitmap(size, size, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            using(Graphics g = Graphics.FromImage(resizedImage))
            {
                //g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default;

                g.DrawImage(originalImage, 0, 0, size, size);
                g.Dispose();
            }*/


            return resizedImage;
        }


        public static Icon ImageToIcon(Image image, int iconWidth = 256, int iconHeight = 256)
        {
            try
            {
                using(Bitmap bitmap = new Bitmap(image, iconWidth, iconHeight))
                {
                    using(Icon icon = Icon.FromHandle(bitmap.GetHicon()))
                    {                      
                        return icon;
                    }
                }
            }
            catch(Exception)
            {
            }
            return null;
        }
    }
}
